using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace ModWatch
{

	/// <summary>
	/// A <see cref="ModWatch.ModWatcherExtenderBase"/> control
	/// that tracks changes to a <see cref="System.Web.UI.WebControls.CheckBoxList"/>.
	/// </summary>
	[TargetControlType(typeof(CheckBoxList))]
	public class CheckBoxListModWatcherExtender : ModWatcherExtenderBase
	{

		/// <summary>
		/// The checked indices of the targeted
		/// <see cref="System.Web.UI.WebControls.CheckBox"/>
		/// at the time that it was last saved.
		/// </summary>
		private List<int> SavedIndices
		{
			get
			{
				if (ViewState["SavedIndices"] == null)
					ViewState["SavedIndices"] = new List<int>();
				return (List<int>)ViewState["SavedIndices"];
			}
		}

		/// <summary>
		/// Raises the <see cref="System.Web.UI.Control.Init"/> event.
		/// </summary>
		/// <param name="e">
		/// An <see cref="System.EventArgs"/>
		/// object that contains event data.
		/// </param>
		protected override void OnInit(EventArgs e)
		{
			base.OnInit(e);

			this.GettingScriptReferences += new EventHandler<ScriptReferencesEventArgs>(this_GettingScriptReferences);
		}

		/// <summary>
		/// Returns a value indicating whether the value of the targeted
		/// <see cref="System.Web.UI.WebControls.CheckBoxList"/> has changed since it was last saved.
		/// </summary>
		/// <returns>true if a change has been detected, false otherwise.</returns>
		protected override bool HasBeenChanged()
		{
			CheckBoxList cbl = TargetControl as CheckBoxList;

			List<int> selIndices = GetSelectedIndices(cbl);

			if (!IsListSubset<int>(this.SavedIndices, selIndices))
				return true;
			if (!IsListSubset<int>(selIndices, this.SavedIndices))
				return true;
			return false;
		}

		/// <summary>
		/// Returns the selected indices of the provided
		/// <see cref="System.Web.UI.WebControls.CheckBoxList"/>.
		/// </summary>
		/// <param name="List">The <see cref="System.Web.UI.WebControls.CheckBoxList"/>.</param>
		/// <returns>
		/// A <see cref="List&lt;T>"/> of <see cref="int"/> containing the selected indices.
		/// </returns>
		private List<int> GetSelectedIndices(CheckBoxList List)
		{
			List<int> selValues = new List<int>();

			for (int i = 0; i < List.Items.Count; i++)
			{
				if (List.Items[i].Selected)
					selValues.Add(i);
			}

			return selValues;
		}

		/// <summary>
		/// Returns a value indicating whether one
		/// <see cref="List&lt;T>"/> is a subset of another.
		/// </summary>
		/// <typeparam name="T">
		/// The type of lists to be compared.
		/// </typeparam>
		/// <param name="Superset">
		///	The list to be checked to contain the Subset.
		/// </param>
		/// <param name="Subset">
		/// The list to be checked as the subset.
		/// </param>
		/// <returns>true if Subset is a subset of Superset, false otherwise.</returns>
		private bool IsListSubset<T>(List<T> Superset, List<T> Subset)
		{
			foreach (T item in Subset)
			{
				if (!Superset.Contains(item))
					return false;
			}
			return true;
		}

		/// <summary>
		/// Saves the current value of the targeted
		/// <see cref="System.Web.UI.WebControls.CheckBoxList"/>.
		/// </summary>
		public override void SaveTargetState()
		{
			CheckBoxList cbl = TargetControl as CheckBoxList;
			SavedIndices.Clear();
			SavedIndices.AddRange(GetSelectedIndices(cbl));
		}

		/// <summary>
		/// Returns the <see cref="System.Web.UI.ScriptDescriptor"/>s required by
		/// this instance of <see cref="ModWatch.CheckBoxListModWatcherExtender"/>.
		/// </summary>
		/// <param name="targetControl">
		/// The <see cref="System.Web.UI.WebControls.CheckBoxList"/> control being targeted.
		/// </param>
		/// <returns>
		/// A collection of <see cref="System.Web.UI.ScriptDescriptor"/>s
		/// defining this instance of <see cref="ModWatch.CheckBoxListModWatcherExtender"/>.
		/// </returns>
		protected override IEnumerable<ScriptDescriptor> GetScriptDescriptors(Control targetControl)
		{
			ScriptBehaviorDescriptor sbd = new ScriptBehaviorDescriptor("ModWatch.CheckBoxListModWatcherBehavior", targetControl.ClientID);
			sbd.AddProperty("modGroup", this.ModGroup);

			sbd.AddProperty("valuesToCompare", SavedIndices);

			return new ScriptDescriptor[] { sbd };
		}

		/// <summary>
		/// Registers the scripts needed by the
		/// <see cref="ModWatch.CheckBoxListModWatcherExtender"/> class.
		/// </summary>
		/// <param name="sender">
		/// The <see cref="System.Object"/> that fired the
		/// <see cref="ModWatch.ModWatchExtenderBase.GettingScriptReferences"/> event.
		/// </param>
		/// <param name="e">
		/// A <see cref="ModWatch.ScriptReferencesEventArgs"/> object that contains the event data.
		/// </param>
		private void this_GettingScriptReferences(object sender, ScriptReferencesEventArgs e)
		{
			e.AddWebResourceScriptReference("ModWatch.Scripts.CheckBoxListModWatcherBehavior.js");
		}

	}

}
